// +----------------------------------------------------------------------
// | CodeEngine
// +----------------------------------------------------------------------
// | Copyright 艾邦
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: TaoGe <liangtao.gz@foxmail.com>
// +----------------------------------------------------------------------
// | Version: 2.0 2019/4/2 13:47
// +----------------------------------------------------------------------
'use strict';

import qs from 'qs';
import Tool from "./tool";

export default class Request {

  static config;
  static helper;
  static storage;
  static interface;

  constructor(config, storage, helper, interfaces) {
    if (Tool.empty(config)) {
      throw new SyntaxError('Request实例化config不能为空')
    }
    if (Tool.empty(storage)) {
      throw new SyntaxError('Request实例化storage不能为空')
    }
    if (Tool.empty(helper)) {
      throw new SyntaxError('Request实例化helper不能为空')
    }
    if (Tool.empty(interfaces)) {
      throw new SyntaxError('Request实例化interfaces不能为空')
    }
    Request.config = config;
    Request.helper = helper;
    Request.storage = storage;
    Request.interface = interfaces;
  }

  static getInstance(config, storage, helper, interfaces) {
    if (!this.instance) {
      this.instance = new Request(config, storage, helper, interfaces);
    }
    return this.instance;
  }

  /**
   * 发送网络请求
   *
   * @param {string}  url     请求d地址
   * @param {object}  options 参数集,默认{Methods:GET},支持GET, POST, PATCH, PUT, DELETE
   * @param {object}  cb 回调方法对象
   * @returns {Promise}
   */
  async sendRaytheonRequest(url, options = {}, cb = {}) {

    // 请求地址
    let api = Request.config.host + url;
    console.log(new Date(), api);
    // 设置请求的 HEADER
    const header = Object.assign({method: 'GET', headers: {}, credentials: 'include'}, options);

    // 登录授权Token
    const token = await Request.helper.token;
    if (!Tool.empty(token)) {
      header.headers.Authorization = token;
    }

    // 终端信息
    header.headers[ 'Api-Terminal' ] = Request.config.terminal;

    // 版本信息
    header.headers[ 'Api-Version' ] = Request.config.version;

    // 参数加密
    const data = Request.interface.formatData(header.body);

    // GET或者HEAD请求单独处理
    const method = String(header.method).toUpperCase();
    if (method === 'GET' || method === 'HEAD') {
      api = api + '?' + qs.stringify(JSON.parse(data));
      delete header.body;
    } else {
      header.body = data;
      header.headers[ 'Content-Type' ] = 'application/json';
    }

    // 请求函数
    return fetch(api, header)
      .then(Request.checkStatus)
      .then(Request.checkReferer)
      .then(Request.parseJSON)
      .then(Request.closeLoad)
      .then(Request.checkCode)
      .then(Request.checkCSRF)
      .then(Request.checkTime)
      .then(Request.checkSignature)
      .then(res => Request.callback(res, cb))
      .catch(error => console.warn(error));
  }

  // 超时验证
  static checkTime(data) {
    // API网络请求是否超时
    if (Request.config.times_out > 0) {
      if (!Tool.empty(data.timestamps) && ( ( new Date().getTime() / 1000 ) - data.timestamps ) <= Request.config.times_out) {
        return data
      }
      throw new Error('网络请求已超时');
    } else {
      return data
    }
  }

  // 签名验证
  static checkSignature(data) {
    if (Request.interface.checkSign(data)) {
      return data.data
    }
    throw new Error('Sign 错误');
  }

  // 防止跨站点请求伪造
  static checkCSRF(data) {
    if (Request.interface.checkState(data)) {
      return data
    }
    throw new Error('State 错误');
  }

  // Referer
  static checkReferer(response) {
    const referer = Tool.domainName(response.url);
    if (referer === Request.config.referer) {
      return response;
    }
    throw new Error('Referer 错误');
  }

  // 返回码异常校验
  static checkCode(response) {
    if (typeof response.code === 'number') {
      if (response.code === 0) {
        return response
      }
      Tool.errorCodeThrow(response);
    }
    throw new Error('服务器返回数据结构异常，内容如下：' + "\r\n" + JSON.stringify(response));
  }

  // 关闭loading
  static closeLoad(response) {
    return response;
  }

  // 解析JSON
  static parseJSON(response) {
    if (typeof response === 'object' && String(response.headers.get('Request-Method')).toUpperCase() !== 'HEAD') {
      const contentType = String(response.headers.get('content-type')).toLowerCase();
      if (contentType.indexOf('application/json') !== - 1) {
        return response.json();
      } /*else if ( contentType.indexOf( 'text/htm' ) !== -1 ) {
				response.text().then( text => throw new Error( text ) );
			}*/
      throw new Error('网络请求返回格式异常：' + contentType);
    }
    throw new Error(response.statusText);
  }

  // 检测状态码
  static checkStatus(response) {
    if (response.status >= 200 && response.status < 300) {
      return response;
    }
    throw new Error(response.statusText);
  }

  // 回调方法
  static callback(response, cb) {
    if (cb === {}) {
      return response;
    }
    const callback = Object.assign({
      success: function (res) {
      },
      fail: function (res) {
      },
      complete: function (res) {
      }
    }, cb);
    if (typeof response !== 'object') {
      throw new Error(response.toString());
    }
    if (response.status && String(response.status).toLowerCase() === 'ok') {
      callback.success(response)
    } else {
      callback.fail(response)
    }
    callback.complete(response);
    return response;
  }
}
